#ifndef __DB_HPP
#define __DB_HPP

#include "logger.hpp"
#include "util.hpp"
#include <pthread.h>
#include <mutex>
#include <assert.h>

class user_table
{
public:
    user_table(const std::string &host,
               const std::string &username,
               const std::string &password,
               const std::string &dbname,
               uint16_t port = 3306);

    bool insert(Json::Value& user);//注册新增用户
    bool login(Json::Value& user);//登录验证，并且返回详细用户信息
    bool select_by_name(const std::string& name,Json::Value& user);//通过用户名获取用户信息
    bool select_by_id(uint64_t id,Json::Value& user);//通过id获取用户信息
    bool win(uint64_t id);//胜利时天梯分数增加，战斗场次增加，胜利场次增加
    bool lose(uint64_t id);//失败时天梯分数减少，战斗场次增加，其他不变
    ~user_table();

private:
    MYSQL* _mysql;//mysql操作句柄
    std::mutex _mutex;//互斥锁保护数据库的访问操作
};


user_table::user_table(const std::string &host,
        const std::string &username,
        const std::string &password,
        const std::string &dbname,
        uint16_t port)
{
    _mysql = mysql_util::mysql_create(host,username,password,dbname,port);
    assert(_mysql != nullptr);
}

//注册新增用户
bool user_table::insert(Json::Value& user)
{
    #define INSERT_USER "insert user values(null,'%s',password('%s'), 1000, 0, 0);"

    // Json::Value val;
    // bool ret = select_by_name(user["username"].asCString(),val);
    // if(ret == true)
    // {
    //     DLOG("user:%s already exists",user["username"].asCString());
    //     return false;
    // }


    char sql[4096] = {0};
    sprintf(sql,INSERT_USER,user["username"].asCString(),user["password"].asCString());
    bool ret = mysql_util::mysql_exec(_mysql,sql);
    if(ret == false)
    {
        DLOG("insert user info failed!!!!");
        ILOG("新增用户失败！！！");
        return false;
    }
    ILOG("新增用户成功！！！");
    return true;
}

//登录验证，并且返回详细用户信息
bool user_table::login(Json::Value& user)
{
    if(user["username"].isNull() || user["password"].isNull())
    {
        DLOG("INPUT USERNAME OR PASSWORD");
        ILOG("请输入用户名和密码");
        return false;
    }

    #define LOGIN_USER "select id,score,total_count,win_count from user where username='%s' and password=password('%s');"
    char sql[4096] = {0};
    sprintf(sql,LOGIN_USER,user["username"].asCString(),user["password"].asCString());
    MYSQL_RES* res = nullptr;
    {
        std::unique_lock<std::mutex> lock(_mutex);
        bool ret = mysql_util::mysql_exec(_mysql,sql);
        if(ret == false)
        {
            DLOG("user login failed!!!!");
            ILOG("查询用户失败！！！");
            return false;
        }
  
        ILOG("查询用户成功！！！");

        res = mysql_store_result(_mysql);
        if(res == nullptr)
        {
            DLOG("have no login user info!!!!");
            ILOG("没有用户");

            return false;
        }
    }

    int row_num = mysql_num_rows(res);
    if(row_num != 1)
    {
        DLOG("login user info unique!!!!");
        ILOG("结果不唯一");
        return false;
    }

    MYSQL_ROW row = mysql_fetch_row(res);
    user["id"] = (Json::UInt64)std::stol(row[0]);
    user["score"] = (Json::UInt64)std::stol(row[1]);
    user["total_count"] = std::stoi(row[2]);
    user["win_count"] = std::stoi(row[3]);
    mysql_free_result(res);
    return true;
}

//通过用户名获取用户信息
bool user_table::select_by_name(const std::string& name,Json::Value& user)
{
    #define USER_BY_NAME "select id,score,total_count,win_count from user where username='%s';"
    char sql[4096] = {0};   
    sprintf(sql,USER_BY_NAME,name.c_str());

    MYSQL_RES* res = nullptr;
    
    {
        std::unique_lock<std::mutex> lock(_mutex);

        bool ret = mysql_util::mysql_exec(_mysql,sql);
        if(ret == false)
        {
            DLOG("get user by name failed!!!!");
            ILOG("查询用户名失败！！！");
            return false;
        }

        ILOG("查询用户名成功！！！");

        res = mysql_store_result(_mysql);
        if(res == nullptr)
        {
            DLOG("have no user info!!!!");
            ILOG("没有用户信息");
            return false;
        }
    }

    int row_num = mysql_num_rows(res);
    if(row_num != 1)
    {
        DLOG("login user info unique!!!!");
        ILOG("结果不唯一");
        return false;
    }
    MYSQL_ROW row = mysql_fetch_row(res);
    user["id"] = (Json::UInt64)std::stol(row[0]);
    user["username"] = name;
    user["score"] = (Json::UInt64)std::stol(row[1]);
    user["total_count"] = std::stoi(row[2]);
    user["win_count"] = std::stoi(row[3]);
    mysql_free_result(res);
    return true;
}

//通过id获取用户信息
bool user_table::select_by_id(uint64_t id,Json::Value& user)
{
    #define USER_BY_ID "select username,score,total_count,win_count from user where id='%ld';"
    char sql[4096] = {0};   
    sprintf(sql,USER_BY_ID,id);

    MYSQL_RES* res = nullptr;
    
    {
        std::unique_lock<std::mutex> lock(_mutex);

        bool ret = mysql_util::mysql_exec(_mysql,sql);
        if(ret == false)
        {
            DLOG("get user by di failed!!!!");
            ILOG("查询用户id失败！！！");
            return false;
        }

        ILOG("查询用户名成功！！！");

        res = mysql_store_result(_mysql);
        if(res == nullptr)
        {
            DLOG("have no user info!!!!");
            ILOG("没有用户信息");
            return false;
        }
    }

    int row_num = mysql_num_rows(res);
    if(row_num != 1)
    {
        DLOG("login user info unique!!!!");
        ILOG("结果不唯一");
        return false;
    }
    MYSQL_ROW row = mysql_fetch_row(res);
    user["id"] = id;
    user["username"] = row[0];
    user["score"] = (Json::UInt64)std::stol(row[1]);
    user["total_count"] = std::stoi(row[2]);
    user["win_count"] = std::stoi(row[3]);
    mysql_free_result(res);
    return true;
}

//胜利时天梯分数增加，战斗场次增加，胜利场次增加
bool user_table::win(uint64_t id)
{
    #define USER_WIN "update user set score=score+30,total_count=total_count+1,win_count=win_count+1 where id=%ld;"
    char sql[4096] = {0};
    sprintf(sql,USER_WIN,id);
    bool ret = mysql_util::mysql_exec(_mysql,sql);
    if(ret == false)
    {
        DLOG("update win user info failed!!!!");
        ILOG("更新用户胜利时操作失败");
        return false;
    }
    ILOG("更新用户胜利时操作成功");
    return true;
}

//失败时天梯分数减少，战斗场次增加，其他不变
bool user_table::lose(uint64_t id)
{
    #define USER_LOSE "update user set score=score-30,total_count=total_count+1 where id=%ld;"
    char sql[4096] = {0};
    sprintf(sql,USER_LOSE,id);
    bool ret = mysql_util::mysql_exec(_mysql,sql);
    if(ret == false)
    {
        DLOG("update lose user info failed!!!!");
        ILOG("更新用户失败时操作失败");
        return false;
    }
    ILOG("更新用户失败时操作成功");
    return true;
}

user_table::~user_table()
{
    mysql_util::mysql_destroy(_mysql);
    _mysql = nullptr;
}

#endif
